#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<ctype.h>
#define LINE_SIZE 1024
#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define ARGC_SIZE 32
#define DELIM " "
#define EXIT_CODE 44
#define IN_RDIR 0
#define OUT_RDIR 1
#define NONE -1
#define APPEND_RDIR 2
char pwd[LINE_SIZE];
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];
int status =0;
int lastcode = 0;
char *rdirfilename = NULL;
int rdir = NONE;
extern char ** environ;
void getpwd()
{
  getcwd(pwd,sizeof(pwd));
}

const char*getusername()
{
  return getenv("USER");
}

const char*getname()
{
  return getenv("HOSTNAME");
}

void check_redir(char *cmd)
{
   char *pos =cmd;
   while(*pos){
     if(*pos=='>'){
       if(*(pos+1)=='>'){
         *pos++='\0';
         *pos++='\0';
         while(isspace(*pos)) pos++;
          rdirfilename=pos;
          rdir=APPEND_RDIR;
          break;
     }
       else{
       *pos='\0';
       pos++;
       while(isspace(*pos)) pos++;
          rdirfilename = pos;
          rdir=OUT_RDIR;
        break;
   }
     }
		else if(*pos=='<'){
      
       *pos='\0';
       pos++;
      while(isspace(*pos)) pos++;
      rdirfilename=pos;
      rdir=IN_RDIR;
			break;
}
else{

}
pos++;
}
}
void interact(char *cline,int size)
{
    getpwd();
    printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(), getname(), pwd);
    char *s=fgets(cline,size,stdin);
    assert(s);
    (void)s;
    cline[strlen(cline)-1]='\0';
    check_redir(cline);
}

int splitstring(char *_argv,char *cline)
{
  int i=0;
  argv[i++]=strtok(cline,DELIM);
  while(argv[i++]=strtok(NULL,DELIM));
  return i-1;
}
void NormalExcute(char* _argv[])
{
  pid_t id =fork();
  if(id<0)
  {
    perror("fork");
    return;
  }
  else if(id == 0){
    int fd=0;
    if(rdir==IN_RDIR){
       fd=open(rdirfilename,O_RDONLY);
      dup2(fd,0);
    }
    else if(rdir==OUT_RDIR){

       fd=open(rdirfilename,O_CREAT|O_WRONLY|O_TRUNC,0666);
      dup2(fd,1);
    }
    else if(rdir==APPEND_RDIR){

       fd=open(rdirfilename,O_CREAT|O_APPEND|O_WRONLY,0666);
      dup2(fd,1);
    }

    execvpe(argv[0],argv,environ);
    exit(EXIT_CODE);
  }
  else{
    int ret = waitpid(id,&status,0);
    if(ret == id){
      lastcode = WEXITSTATUS(status);
    }
  }
}

  
int BulidCommand(int _argc,char * argv[])
{
//  printf("-------------------\n");
//  printf("%s\n",argv[1]);
  if(_argc ==2 && strcmp(argv[0],"cd")==0){  
    chdir(argv[1]);
    getpwd();
    sprintf(getenv("PWD"),"%s",pwd);
    return 1;
  }
  if(_argc == 2 && strcmp(argv[0],"export")==0){
    char *tmp = (char*)malloc(sizeof(char*));
    strcpy(tmp,argv[1]);
    putenv(argv[1]);
    return 1;
  }
if(_argc == 2 && strcmp(argv[0],"ls")==0){
  argv[_argc++]="--color";
  argv[_argc]=NULL;
}

if(_argc==2&&strcmp(argv[0],"echo")==0){
  
      if(strcmp(argv[1], "$?") == 0)
        {
            printf("%d\n", lastcode);
            lastcode=0;
        }
        else if(strcmp(argv[1],"$")==0){
            char *val = getenv(argv[1]+1);
            if(val) printf("%s\n", val);
        }
        else{
            printf("%s\n", argv[1]);
        } 
  
  return 1;
}
  return 0;
}
int main(){
  int quit=0;
  while(!quit)
  {
  //1.获取命令行
  interact(commandline,sizeof(commandline));
   
  //2.字符分割
 int argc =  splitstring(argv,commandline);
 if(argc==0)continue;

  //3.指令的判断 
// for(int i = 0; argv[i]; i++) printf("[%d]: %s\n", i, argv[i]);

  //4.指令执行  
   int n= BulidCommand(argc,argv);
    if(!n)NormalExcute(argv);
  }
}
